package cn.org.wifit.core.zookeeper.handle;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.List;

import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import cn.org.wifit.core.entity.xml.IPX;
import cn.org.wifit.core.utils.JSONUtils;
import cn.org.wifit.core.zookeeper.NodeReadWatcherHandle;
import cn.org.wifit.core.zookeeper.ServerNodeTree;

public class IMUserWatcherHandle implements NodeReadWatcherHandle {
	private ZooKeeper zk;
	

	public ZooKeeper getZk() {
		return zk;
	}

	public void setZk(ZooKeeper zk) {
		this.zk = zk;
	}

	/* (non-Javadoc)
	 * @see cn.org.wifit.core.zookeeper.NodeReadWatcherHandle#doServerIpxChanged(java.lang.String)
	 */
	@Override
	public void doServerIpxChanged(String parentPath) throws Exception {
		/*
		 * 按照设计IMUserWatcherHandle不可能监听到这样的情况，这个方法体里面直接空着就行
		 * */
	}

	/* (non-Javadoc)
	 * @see cn.org.wifit.core.zookeeper.NodeReadWatcherHandle#doServerChanged()
	 */
	@Override
	public void doServerChanged() throws Exception {
		/*
		 * 按照设计IMUserWatcherHandle不可能监听到这样的情况，这个方法体里面直接空着就行
		 * */
	}

	/* (non-Javadoc)
	 * @see cn.org.wifit.core.zookeeper.NodeReadWatcherHandle#doUserIpxChanged(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void doUserIpxChanged(String parentPath) throws Exception {
		/*
		 * 由于监控特性，我们并不知道是/IMUser/ipxs下的哪个ipx节点发生了变化，只知道上一级的节点信息（从parentPath得到）
		 * 我们也不是到是增加了一个ipx还是减少了一个ipx
		 * 所以，处理过程为：
		 * 1、从本地ServerNodeTree得到当前user下的所有ipx信息
		 * 2、从远程zookeeper上面得到所有的/IMUser/ipxs下所有ipx的信息
		 * 3、以zookeeper上得到的ipx为基础，比较本地ipx。
		 * 	如果最后发现本地ipx多出，则表示是远程ipx减少了，删除本地多出来的即可
		 * 	如果最后发现远程ipx多出，则表示是远程ipx多出来了，向本地增加新的ipx即可
		 * */
		ServerNodeTree serverNodeTree = ServerNodeTree.getNewInstance();
		String useripsjson = serverNodeTree.GetIMUserServerNodes();
		
		List<IPX> localIPXs = JSONUtils.toBean(useripsjson, IPX.class);
		List<String> zkIPXs = this.zk.getChildren(parentPath, false);
		
		//如果条件成立，说明是远程zookeeper上面有节点增加
		if(localIPXs == null || localIPXs.size() == 0 || localIPXs.size() < zkIPXs.size()) {
			//一般scooper上面增加的节点，都在最后，所以从zkIPXs的最后来检查就行了
			for(int index = zkIPXs.size() - 1 ; index >= 0 ; index--) {
				String ipxpath = zkIPXs.get(0);
				String fullpath = parentPath + "/" + ipxpath;
				String ipxsequence = ipxpath.substring(ipxpath.length() - 10, ipxpath.length());
				
				//如果条件成立，说明新增的节点就是这个了，向serverNodeTree增加，并终止循环即可
				if(!serverNodeTree.isUseripxExist(ipxsequence)) {
					//获取数据
					byte[] databytes = this.zk.getData(fullpath, false, null);
					ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(databytes));
					HashMap<String, Object> ipxdata = (HashMap<String, Object>)in.readObject();
					in.close();
					
					String ip = ipxdata.get("ip").toString();
					Integer port = (Integer)ipxdata.get("port");
					
					//开始添加
					serverNodeTree.AddIMUserServerNode(ipxsequence, ip, port);
					break;
				}
			}
		}
		
		//如果条件成立，说明是远程zookeeper上面有节点减少
		else if(zkIPXs == null || zkIPXs.size() == 0 || zkIPXs.size() < localIPXs.size()) {
			//由于不知道server下的哪个ipx减少了，所以基于localIPXs从第一个开始检查
			for(int index = 0 ; index < localIPXs.size() ; index++) {
				IPX localIpx = localIPXs.get(index);
				String ipxsequence = localIpx.getSequence();
				String fullpath = parentPath + "/ipx" + ipxsequence;
				
				//判断远程有没有
				Stat stat = this.zk.exists(fullpath, false);
				//如果条件成立，说明远程zk没有
				if(stat == null) {
					serverNodeTree.removeIMUserServer(ipxsequence);
					break;
				}
			}
		}
	}
}
